package com.skyeye;

import com.skyeye.entity.User;
import com.skyeye.mapper.UserMapper;
import com.skyeye.util.DatabaseUtil;
import com.skyeye.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import static org.junit.Assert.*;

/**
 * 使用MyBatis进行用户CRUD操作的单元测试类
 * 通过.properties配置文件配置数据库连接
 */
public class UserMyBatisTest {
    
    private SqlSession sqlSession;
    private UserMapper userMapper;
    
    @Before
    public void setUp() {
        // 创建测试表
//        DatabaseUtil.createTestTable();
        
        // 获取SqlSession和Mapper
        sqlSession = MyBatisUtil.getSqlSession();
        userMapper = sqlSession.getMapper(UserMapper.class);
        
        System.out.println("🚀 开始执行MyBatis CRUD测试...");
    }
    
    @After
    public void tearDown() {
        // 清空测试数据
//        DatabaseUtil.truncateTestTable();
        
        // 关闭SqlSession
        MyBatisUtil.closeSqlSession(sqlSession);
        
        System.out.println("🧹 MyBatis测试完成，清理测试数据");
    }
    
    /**
     * 测试插入用户（Create）
     */
    @Test
    public void testInsertUser() {
        // 准备测试数据
        User testUser = new User("张三1", "zhangsan@example.com", 25, "13800138000");
        testUser.setCreateTime(LocalDateTime.now());
        testUser.setUpdateTime(LocalDateTime.now());
        
        // 执行插入
        int affectedRows = userMapper.insertUser(testUser);
        
        // 验证结果
        assertEquals("应该插入1条记录", 1, affectedRows);
        assertNotNull("用户ID应该被设置", testUser.getId());
        
        System.out.println("✅ MyBatis用户插入成功！ID: " + testUser.getId());
        System.out.println("插入的用户信息: " + testUser);
    }
    
    /**
     * 测试根据ID查询用户（Read）
     */
    @Test
    public void testSelectUserById() {
        // 先插入测试数据
        User testUser = createTestUser("李四", "lisi@example.com", 30, "13900139000");
        
        // 执行查询
        User foundUser = userMapper.selectUserById(testUser.getId());
        
        // 验证结果
        assertNotNull("应该查询到用户", foundUser);
        assertEquals("用户名应该匹配", testUser.getUsername(), foundUser.getUsername());
        assertEquals("邮箱应该匹配", testUser.getEmail(), foundUser.getEmail());
        assertEquals("年龄应该匹配", testUser.getAge(), foundUser.getAge());
        assertEquals("电话应该匹配", testUser.getPhone(), foundUser.getPhone());
        
        System.out.println("✅ MyBatis用户查询成功！");
        System.out.println("查询到的用户信息: " + foundUser);
    }
    
    /**
     * 测试根据用户名查询用户
     */
    @Test
    public void testSelectUserByUsername() {
        // 先插入测试数据
        createTestUser("王五", "wangwu@example.com", 28, "13700137000");
        
        // 执行查询
        User foundUser = userMapper.selectUserByUsername("王五");
        
        // 验证结果
        assertNotNull("应该查询到用户", foundUser);
        assertEquals("用户名应该匹配", "王五", foundUser.getUsername());
        assertEquals("邮箱应该匹配", "wangwu@example.com", foundUser.getEmail());
        
        System.out.println("✅ MyBatis根据用户名查询成功！");
        System.out.println("查询到的用户信息: " + foundUser);
    }
    
    /**
     * 测试更新用户（Update）
     */
    @Test
    public void testUpdateUser() {
        // 先插入测试数据
        User testUser = createTestUser("赵六", "zhaoliu@example.com", 35, "13600136000");
        
        // 修改用户信息
        testUser.setEmail("zhaoliu_new@example.com");
        testUser.setAge(36);
        testUser.setPhone("13600136001");
        testUser.setUpdateTime(LocalDateTime.now());
        
        // 执行更新
        int affectedRows = userMapper.updateUser(testUser);
        
        // 验证结果
        assertEquals("应该更新1条记录", 1, affectedRows);
        
        // 验证更新后的数据
        User updatedUser = userMapper.selectUserById(testUser.getId());
        assertEquals("邮箱应该已更新", "zhaoliu_new@example.com", updatedUser.getEmail());
        assertEquals("年龄应该已更新", Integer.valueOf(36), updatedUser.getAge());
        assertEquals("电话应该已更新", "13600136001", updatedUser.getPhone());
        
        System.out.println("✅ MyBatis用户更新成功！用户ID: " + testUser.getId());
        System.out.println("更新后的用户信息: " + updatedUser);
    }
    
    /**
     * 测试删除用户（Delete）
     */
    @Test
    public void testDeleteUser() {
        // 先插入测试数据
        User testUser = createTestUser("孙七", "sunqi@example.com", 40, "13500135000");
        int userId = testUser.getId();
        
        // 执行删除
        int affectedRows = userMapper.deleteUserById(userId);
        
        // 验证结果
        assertEquals("应该删除1条记录", 1, affectedRows);
        
        // 验证删除后的数据
        User deletedUser = userMapper.selectUserById(userId);
        assertNull("用户应该已被删除", deletedUser);
        
        System.out.println("✅ MyBatis用户删除成功！用户ID: " + userId);
    }
    
    /**
     * 测试查询所有用户
     */
    @Test
    public void testSelectAllUsers() {
        // 插入多条测试数据
        createTestUser("用户1", "user1@example.com", 20, "13100131000");
        createTestUser("用户2", "user2@example.com", 25, "13200132000");
        createTestUser("用户3", "user3@example.com", 30, "13300133000");
        
        // 执行查询
        List<User> users = userMapper.selectAllUsers();
        
        // 验证结果
        assertEquals("应该查询到3个用户", 3, users.size());
        
        System.out.println("✅ MyBatis查询所有用户成功！");
        System.out.println("查询到的用户数量: " + users.size());
        for (User user : users) {
            System.out.println("用户信息: " + user);
        }
    }
    
    /**
     * 测试根据年龄范围查询用户
     */
    @Test
    public void testSelectUsersByAgeRange() {
        // 插入测试数据
        createTestUser("小明", "xiaoming@example.com", 22, "13400134000");
        createTestUser("小红", "xiaohong@example.com", 23, "13500135000");
        createTestUser("小刚", "xiaogang@example.com", 24, "13600136000");
        
        // 执行查询
        List<User> users = userMapper.selectUsersByAgeRange(22, 23);
        
        // 验证结果
        assertEquals("应该查询到2个用户（年龄22-23）", 2, users.size());
        
        System.out.println("✅ MyBatis根据年龄范围查询成功！");
        System.out.println("查询到的用户数量: " + users.size());
        for (User user : users) {
            System.out.println("用户信息: " + user);
        }
    }
    
    /**
     * 测试根据邮箱查询用户
     */
    @Test
    public void testSelectUserByEmail() {
        // 先插入测试数据
        createTestUser("测试用户", "test@example.com", 25, "13700137000");
        
        // 执行查询
        User foundUser = userMapper.selectUserByEmail("test@example.com");
        
        // 验证结果
        assertNotNull("应该查询到用户", foundUser);
        assertEquals("邮箱应该匹配", "test@example.com", foundUser.getEmail());
        
        System.out.println("✅ MyBatis根据邮箱查询成功！");
        System.out.println("查询到的用户信息: " + foundUser);
    }
    
    /**
     * 测试统计用户总数
     */
    @Test
    public void testCountUsers() {
        // 先插入测试数据
        createTestUser("用户A", "usera@example.com", 20, "13100131000");
        createTestUser("用户B", "userb@example.com", 25, "13200132000");
        
        // 执行统计
        int count = userMapper.countUsers();
        
        // 验证结果
        assertEquals("应该统计到2个用户", 2, count);
        
        System.out.println("✅ MyBatis统计用户总数成功！");
        System.out.println("用户总数: " + count);
    }
    
    /**
     * 测试根据用户名模糊查询
     */
    @Test
    public void testSelectUsersByUsernameLike() {
        // 插入测试数据
        createTestUser("张三", "zhangsan@example.com", 25, "13100131000");
        createTestUser("张四", "zhangsi@example.com", 26, "13200132000");
        createTestUser("李五", "liwu@example.com", 27, "13300133000");
        
        // 执行模糊查询
        List<User> users = userMapper.selectUsersByUsernameLike("张");
        
        // 验证结果
        assertEquals("应该查询到2个用户（用户名包含'张'）", 2, users.size());
        
        System.out.println("✅ MyBatis根据用户名模糊查询成功！");
        System.out.println("查询到的用户数量: " + users.size());
        for (User user : users) {
            System.out.println("用户信息: " + user);
        }
    }
    
    /**
     * 测试使用MyBatisUtil工具类的事务管理
     */
    @Test
    public void testTransactionManagement() {
        // 使用事务管理执行多个操作
        MyBatisUtil.executeWithTransaction(sqlSession -> {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            
            // 插入用户1
            User user1 = new User("事务用户1", "transaction1@example.com", 30, "13100131000");
            user1.setCreateTime(LocalDateTime.now());
            user1.setUpdateTime(LocalDateTime.now());
            mapper.insertUser(user1);
            
            // 插入用户2
            User user2 = new User("事务用户2", "transaction2@example.com", 31, "13200132000");
            user2.setCreateTime(LocalDateTime.now());
            user2.setUpdateTime(LocalDateTime.now());
            mapper.insertUser(user2);
            
            // 验证插入结果
            List<User> users = mapper.selectAllUsers();
            assertEquals("事务中应该插入2个用户", 2, users.size());
            
            return users;
        });
        
        System.out.println("✅ MyBatis事务管理测试成功！");
    }
    
    /**
     * 测试批量插入用户
     */
    @Test
    public void testBatchInsertUsers() {
        // 准备批量数据
        List<User> users = new ArrayList<>();
        for (int i = 1; i <= 5; i++) {
            User user = new User("批量用户" + i, "batch" + i + "@example.com", 20 + i, "1380013800" + i);
            user.setCreateTime(LocalDateTime.now());
            user.setUpdateTime(LocalDateTime.now());
            users.add(user);
        }
        
        // 执行批量插入
        int affectedRows = userMapper.batchInsertUsers(users);
        
        // 验证结果
        assertEquals("应该插入5条记录", 5, affectedRows);
        
        // 验证数据
        List<User> allUsers = userMapper.selectAllUsers();
        assertEquals("应该查询到5个用户", 5, allUsers.size());
        
        System.out.println("✅ MyBatis批量插入成功！");
        System.out.println("批量插入的用户数量: " + affectedRows);
        for (User user : allUsers) {
            System.out.println("用户信息: " + user);
        }
    }
    
    /**
     * 辅助方法：创建测试用户并返回用户对象
     */
    private User createTestUser(String username, String email, int age, String phone) {
        User user = new User(username, email, age, phone);
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        
        userMapper.insertUser(user);
        return user;
    }
}
